package com.rock.platform.core;

import java.io.Serializable;
import java.sql.Connection;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceContext;

import com.rock.platform.util.JpaDialectUtils;

public class DefaultJPADao implements IGenericDao {

	@PersistenceContext
	private EntityManager em;

	@SuppressWarnings("unchecked")
	public <T> List<T> findAll(Class<T> entityType) {
		return this.em.createQuery("from " + entityType.getName())
				.getResultList();
	}

	@SuppressWarnings("unchecked")
	public <T, ID extends Serializable> T findByID(ID id, boolean lock,
			Class<T> entityType) {
		Object entity = this.em.find(entityType, id);
		if (lock) {
			this.em.lock(entity, LockModeType.WRITE);
		}

		return (T) entity;
	}

	public <T> void add(T entity) {
		this.em.persist(entity);
		this.em.flush();
	}

	@SuppressWarnings("unchecked")
	public <T> T update(T entity) {
		Object t = merge(entity);
		this.em.flush();
		return (T) t;
	}

	private <T> T merge(T entity) {
		return this.em.merge(entity);
	}

	public <T> void add(T[] entities) {
		merge(entities);
	}

	public <T> void update(T[] entities) {
		merge(entities);
	}

	public <T> void merge(T[] entities) {
		for (int i = 0; i < entities.length; ++i) {
			if ((i % 50 == 0) && (i != 0)) {
				this.em.flush();
				this.em.clear();
			}
			merge(entities[i]);
		}
		this.em.flush();
	}

	public <T> void delete(T entity) {
		delete(entity, true);
	}

	public <T> void delete(T[] entities) {
		for (int i = 0; i < entities.length; ++i) {
			if ((i % 50 == 0) && (i != 0)) {
				this.em.flush();
			}
			delete(entities[i], false);
		}
		this.em.flush();
	}

	private <T> void delete(T entity, boolean flush) {
		this.em.remove(entity);
		if (!(flush))
			return;
		this.em.flush();
	}

	public <T, ID extends Serializable> void deleteByID(ID id,
			Class<T> entityType) {
		deleteByID(id, entityType, true);
	}

	public <T, ID extends Serializable> void deleteByID(ID[] ids,
			Class<T> entityType) {
		for (int i = 0; i < ids.length; ++i) {
			if ((i % 50 == 0) && (i != 0)) {
				this.em.flush();
				this.em.clear();
			}
			deleteByID(ids[i], entityType, false);
		}
		this.em.flush();
	}

	private <T, ID extends Serializable> void deleteByID(ID id,
			Class<T> entityType, boolean flush) {
		this.em.remove(this.em.getReference(entityType, id));
		if (!(flush))
			return;
		this.em.flush();
	}

	public void flush() {
		this.em.flush();
	}

	public void clear() {
		this.em.clear();
	}

	public EntityManager getEntityManager() {
		return this.em;
	}

	public Connection getConnection() {
		return JpaDialectUtils.getConnection(this.em);
	}
}
